; IP header structure
struc ip_header
    .version_ihl    resb 1  ; Version (4 bits) + Internet Header Length (4 bits)
    .tos            resb 1  ; Type of Service
    .total_len      resw 1  ; Total Length
    .id             resw 1  ; Identification
    .flags_offset   resw 1  ; Flags (3 bits) + Fragment Offset (13 bits)
    .ttl            resb 1  ; Time to Live
    .protocol       resb 1  ; Protocol
    .checksum       resw 1  ; Checksum
    .src_ip         resd 1  ; Source IP Address
    .dst_ip         resd 1  ; Destination IP Address
endstruc

section .data
    ; IP header values
    version         equ 4   ; IPv4
    ihl             equ 5   ; Internet Header Length (5 * 32-bit words)
    tos             equ 0   ; Type of Service
    total_len       equ 28  ; Total Length (header + data)
    id              equ 54321  ; Identification
    flags           equ 0   ; Flags (not fragmented)
    frag_offset     equ 0   ; Fragment Offset
    ttl             equ 64  ; Time to Live
    protocol        equ 6   ; Protocol (TCP)
    src_ip          dd 0x6401a8c0  ; Source IP Address (192.168.1.100)
    dst_ip          dd 0x0100000a  ; Destination IP Address (10.0.0.1)

section .bss
    ip_hdr          resb ip_header_size  ; IP header buffer

section .text
    global create_ip_header

; void create_ip_header(uint8_t *buffer)
create_ip_header:
    push ebp
    mov ebp, esp
    push ebx

    ; Prepare IP header fields
    mov eax, version
    shl eax, 4
    or al, ihl
    mov byte [ip_hdr + ip_header.version_ihl], al
    mov byte [ip_hdr + ip_header.tos], tos
    mov [ip_hdr + ip_header.total_len], word total_len
    mov [ip_hdr + ip_header.id], word id
    mov [ip_hdr + ip_header.flags_offset], word (flags << 13) + frag_offset
    mov byte [ip_hdr + ip_header.ttl], ttl
    mov byte [ip_hdr + ip_header.protocol], protocol
    mov word [ip_hdr + ip_header.checksum], 0  ; Checksum (calculated later)
    mov dword [ip_hdr + ip_header.src_ip], src_ip
    mov dword [ip_hdr + ip_header.dst_ip], dst_ip

    ; Calculate IP header checksum
    mov esi, ip_hdr
    call calculate_checksum
    mov [ip_hdr + ip_header.checksum], ax

    ; Copy IP header to the buffer
    mov edi, [ebp + 8]  ; buffer
    mov esi, ip_hdr
    mov ecx, ip_header_size
    cld
    rep movsb

    pop ebx
    pop ebp
    ret

; uint16_t calculate_checksum(uint8_t *data, uint32_t len)
calculate_checksum:
    push ebp
    mov ebp, esp
    push ebx
    push esi

    xor eax, eax  ; Checksum
    xor ebx, ebx  ; Word
    mov ecx, [ebp + 12]  ; len

checksum_loop:
    mov bl, [esi]
    inc esi
    mov bh, [esi]
    inc esi

